package chapter04.part03;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Scanner;

/**
 * 学习向 Web 发送请求
 * 
 * @author insight
 * @since 2021/8/31
 */
public class PostTest {
    public static void main(String[] args) throws IOException {
        InputStream in =
                PostTest.class.getClassLoader().getResourceAsStream("request" +
                        ".properties");
        Properties prop = new Properties();
        
        prop.load(Objects.requireNonNull(in));

        String urlStr = prop.remove("url").toString();
        String userAgent = prop.remove("User-Agent").toString();
        // 配置全局 cookie 处理器
        // 允许 cookie 包含在重定向中转发
        CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
        String ret = doPost(new URL(urlStr), userAgent, prop);
        System.out.println(ret);
    }

    private static String doPost(URL url, String userAgent, Map<Object, Object> prop) throws IOException {
        var connection =
                (HttpURLConnection) url.openConnection();
        
        // 允许提交数据
        // 只有 Post 请求才能输出
        connection.setDoOutput(true);
        connection.setRequestProperty("User-Agent", userAgent);
        // 默认自动处理重定向 关闭重定向 手动检查响应码再决定是否重定向
        connection.setInstanceFollowRedirects(false);
        
        try (PrintWriter out =
                     new PrintWriter(connection.getOutputStream())) {
            boolean flag = true;
            for (Map.Entry<Object, Object> entry : prop.entrySet()) {
                if (flag) flag = false;
                else out.print('&');
                
                String key = entry.getKey().toString();
                String value = entry.getValue().toString();
                out.print(key + '=' + URLEncoder.encode(value, StandardCharsets.UTF_8));
            }
        }

        // 在 getInputStream 里发起请求
        // getContentEncoding getResponseCode 调用了 getInputStream
        // 也就是说此时才发出请求 读取返回数据
        String encoding = connection.getContentEncoding();
        if (encoding == null) encoding = "UTF-8";

        int responseCode = connection.getResponseCode();
        // 检查是否重定向
        if (responseCode == HttpURLConnection.HTTP_MOVED_PERM ||
            responseCode == HttpURLConnection.HTTP_MOVED_TEMP ||
            responseCode == HttpURLConnection.HTTP_SEE_OTHER) {
            String location = connection.getHeaderField("Location");
            if (location != null) {
                URL baseUrl = connection.getURL();
                connection.disconnect();
                return doPost(new URL(baseUrl, location), userAgent, prop);
            }
        }

        StringBuilder ret = new StringBuilder();
        try (Scanner in = new Scanner(connection.getInputStream(), encoding)) {
            while (in.hasNextLine()) {
                ret.append(in.nextLine());
                ret.append("\n");
            }
        } catch (IOException e) {
            // 捕获返回的错误信息
            InputStream err = connection.getErrorStream();
            if (err == null) {
                throw e;
            }
            try (Scanner in = new Scanner(err)) {
                while (in.hasNextLine()) {
                    ret.append(in.nextLine());
                    ret.append("\n");
                }
            }
        }

        return ret.toString();
    }
}